﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Imports System.Workflow.ComponentModel.Serialization

Namespace System.Workflow.ComponentModel.Design
    <DesignerSerializer(GetType(ConnectorLayoutSerializer), GetType(WorkflowMarkupSerializer))> _
    Public Class Connector
        Implements IDisposable
        ' Methods
        Public Sub New(ByVal source As ConnectionPoint, ByVal target As ConnectionPoint)
            If (source Is Nothing) Then
                Throw New ArgumentNullException("source")
            End If
            If (target Is Nothing) Then
                Throw New ArgumentNullException("target")
            End If
            If (Not ConnectionManager.GetConnectorContainer(source.AssociatedDesigner) Is ConnectionManager.GetConnectorContainer(target.AssociatedDesigner)) Then
                Throw New ArgumentException(DR.GetString("Error_Connector1", New Object(0  - 1) {}))
            End If
            Me.source = source
            Me.target = target
        End Sub

        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            Dim connector As Connector = [TryCast](obj,Connector)
            If (connector Is Nothing) Then
                Return False
            End If
            Return ((connector.Source Is Me.source) AndAlso (connector.target Is Me.target))
        End Function

        Friend Shared Function GetConnectorFromSelectedObject(ByVal selectedObject As Object) As Connector
            Dim connector As Connector = Nothing
            Dim info As ConnectorHitTestInfo = [TryCast](selectedObject,ConnectorHitTestInfo)
            If (Not info Is Nothing) Then
                Dim associatedDesigner As FreeformActivityDesigner = [TryCast](info.AssociatedDesigner,FreeformActivityDesigner)
                Dim num As Integer = info.MapToIndex
                If (((Not associatedDesigner Is Nothing) AndAlso (num >= 0)) AndAlso (num < associatedDesigner.Connectors.Count)) Then
                    connector = associatedDesigner.Connectors.Item(num)
                End If
            End If
            Return connector
        End Function

        Public Overrides Function GetHashCode() As Integer
            If ((Not Me.source Is Nothing) AndAlso (Not Me.target Is Nothing)) Then
                Return (Me.source.GetHashCode Xor Me.target.GetHashCode)
            End If
            Return MyBase.GetHashCode
        End Function

        Protected Overridable Function GetService(ByVal serviceType As Type) As Object
            Dim service As Object = Nothing
            If (((Not Me.parentDesigner Is Nothing) AndAlso (Not Me.parentDesigner.Activity Is Nothing)) AndAlso (Not Me.parentDesigner.Activity.Site Is Nothing)) Then
                service = Me.parentDesigner.Activity.Site.GetService(serviceType)
            End If
            Return service
        End Function

        Public Overridable Function HitTest(ByVal point As Point) As Boolean
            Dim selectionSize As Size = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize
            Dim connectorSegments As ReadOnlyCollection([Of] Point) = Me.ConnectorSegments
            Dim i As Integer
            For i = 1 To connectorSegments.Count - 1
                Dim line As Point() = New Point() { connectorSegments.Item((i - 1)), connectorSegments.Item(i) }
                If DesignerGeometryHelper.PointOnLineSegment(point, line, selectionSize) Then
                    Return True
                End If
            Next i
            Return False
        End Function

        Public Sub Invalidate()
            Dim parentView As WorkflowView = Me.ParentView
            If (Not parentView Is Nothing) Then
                parentView.InvalidateLogicalRectangle(Me.Bounds)
            End If
        End Sub

        Public Overridable Sub Offset(ByVal size As Size)
            Dim i As Integer
            For i = 0 To Me.segments.Count - 1
                Dim point As Point = Me.segments.Item(i)
                Dim point2 As Point = Me.segments.Item(i)
                Me.segments.Item(i) = New Point((point.X + size.Width), (point2.Y + size.Height))
            Next i
        End Sub

        Protected Friend Overridable Sub OnLayout(ByVal e As ActivityDesignerLayoutEventArgs)
            If ((Me.segments.Count > 0) AndAlso ((Not Me.segments.Item(0) Is Me.Source.Location) OrElse (Not Me.segments.Item((Me.segments.Count - 1)) Is Me.Target.Location))) Then
                Me.connectorModified = False
            End If
            If (Not Me.connectorModified AndAlso (Not Me.ParentDesigner Is Nothing)) Then
                Dim collection As Point() = ActivityDesignerConnectorRouter.Route(Me.Source.AssociatedDesigner.Activity.Site, Me.Source, Me.Target, Me.ExcludedRoutingRectangles)
                Me.segments.Clear
                Me.segments.AddRange(collection)
            End If
        End Sub

        Protected Friend Overridable Sub OnPaint(ByVal e As ActivityDesignerPaintEventArgs)
            Dim designerTheme As CompositeDesignerTheme = [TryCast](e.DesignerTheme,CompositeDesignerTheme)
            If (Not designerTheme Is Nothing) Then
                Dim connectorCapSize As New Size((designerTheme.ConnectorSize.Width / 5), (designerTheme.ConnectorSize.Height / 5))
                Dim connectorSize As Size = designerTheme.ConnectorSize
                ActivityDesignerPaint.DrawConnectors(e.Graphics, e.DesignerTheme.ForegroundPen, New List([Of] Point)(Me.ConnectorSegments).ToArray, connectorCapSize, connectorSize, designerTheme.ConnectorStartCap, designerTheme.ConnectorEndCap)
            End If
        End Sub

        Protected Friend Overridable Sub OnPaintEdited(ByVal e As ActivityDesignerPaintEventArgs, ByVal segments As Point(), ByVal segmentEditPoints As Point())
            Dim designerTheme As CompositeDesignerTheme = [TryCast](e.DesignerTheme,CompositeDesignerTheme)
            If (Not designerTheme Is Nothing) Then
                [Using] pen As Pen = New Pen(e.AmbientTheme.SelectionForegroundPen.Color, e.AmbientTheme.SelectionForegroundPen.Width)
                    pen.DashStyle = DashStyle.Dash
                    Dim connectorCapSize As New Size((designerTheme.ConnectorSize.Width / 5), (designerTheme.ConnectorSize.Height / 5))
                    Dim connectorSize As Size = designerTheme.ConnectorSize
                    ActivityDesignerPaint.DrawConnectors(e.Graphics, pen, segments, connectorCapSize, connectorSize, designerTheme.ConnectorStartCap, designerTheme.ConnectorEndCap)
                End [Using]
                If (Not Me.source Is Nothing) Then
                    Me.source.OnPaint(e, False)
                End If
                Dim i As Integer
                For i = 1 To (segments.Length - 1) - 1
                    Me.PaintEditPoints(e, segments(i), False)
                Next i
                Dim j As Integer
                For j = 0 To segmentEditPoints.Length - 1
                    Me.PaintEditPoints(e, segmentEditPoints(j), True)
                Next j
                If (Not Me.target Is Nothing) Then
                    Me.target.OnPaint(e, False)
                End If
            End If
        End Sub

        Protected Friend Overridable Sub OnPaintSelected(ByVal e As ActivityDesignerPaintEventArgs, ByVal primarySelection As Boolean, ByVal segmentEditPoints As Point())
            Dim designerTheme As CompositeDesignerTheme = [TryCast](e.DesignerTheme,CompositeDesignerTheme)
            If (Not designerTheme Is Nothing) Then
                [Using] pen As Pen = New Pen(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionForeColor, 1!)
                    Dim connectorCapSize As New Size((designerTheme.ConnectorSize.Width / 5), (designerTheme.ConnectorSize.Height / 5))
                    Dim connectorSize As Size = designerTheme.ConnectorSize
                    ActivityDesignerPaint.DrawConnectors(e.Graphics, pen, New List([Of] Point)(Me.ConnectorSegments).ToArray, connectorCapSize, connectorSize, designerTheme.ConnectorStartCap, designerTheme.ConnectorEndCap)
                End [Using]
                If (Not Me.source Is Nothing) Then
                    Me.source.OnPaint(e, False)
                End If
                Dim connectorSegments As ReadOnlyCollection([Of] Point) = Me.ConnectorSegments
                Dim i As Integer
                For i = 1 To (connectorSegments.Count - 1) - 1
                    Me.PaintEditPoints(e, connectorSegments.Item(i), False)
                Next i
                Dim j As Integer
                For j = 0 To segmentEditPoints.Length - 1
                    Me.PaintEditPoints(e, segmentEditPoints(j), True)
                Next j
                If (Not Me.target Is Nothing) Then
                    Me.target.OnPaint(e, False)
                End If
            End If
        End Sub

        Private Sub PaintEditPoints(ByVal e As ActivityDesignerPaintEventArgs, ByVal point As Point, ByVal drawMidSegmentEditPoint As Boolean)
            Dim size As Size = If((Not Me.source Is Nothing), Me.source.Bounds.Size, Size.Empty)
            If Not size.IsEmpty Then
                Dim rect As New Rectangle((point.X - (size.Width / 2)), (point.Y - (size.Height / 2)), size.Width, size.Height)
                If drawMidSegmentEditPoint Then
                    [Using] path As GraphicsPath = New GraphicsPath
                        path.AddLine(New Point((rect.Left + (rect.Width / 2)), rect.Top), New Point(rect.Right, (rect.Top + (rect.Height / 2))))
                        path.AddLine(New Point(rect.Right, (rect.Top + (rect.Height / 2))), New Point((rect.Left + (rect.Width / 2)), rect.Bottom))
                        path.AddLine(New Point((rect.Left + (rect.Width / 2)), rect.Bottom), New Point(rect.Left, (rect.Top + (rect.Height / 2))))
                        path.AddLine(New Point(rect.Left, (rect.Top + (rect.Height / 2))), New Point((rect.Left + (rect.Width / 2)), rect.Top))
                        e.Graphics.FillPath(Brushes.White, path)
                        e.Graphics.DrawPath(e.AmbientTheme.SelectionForegroundPen, path)
                        Return
                    End [Using]
                End If
                rect.Inflate(-1, -1)
                e.Graphics.FillEllipse(e.AmbientTheme.SelectionForegroundBrush, rect)
            End If
        End Sub

        Protected Sub PerformLayout()
            Dim parentView As WorkflowView = Me.ParentView
            If (Not parentView Is Nothing) Then
                parentView.PerformLayout(False)
            End If
        End Sub

        Friend Sub SetConnectorModified(ByVal modified As Boolean)
            Me.connectorModified = modified
        End Sub

        Protected Friend Sub SetConnectorSegments(ByVal segments As ICollection([Of] Point))
            If (segments Is Nothing) Then
                Throw New ArgumentNullException("segments")
            End If
            Me.connectorModified = ((Not Me.parentDesigner Is Nothing) AndAlso (segments.Count > 0))
            If Me.connectorModified Then
                Me.Invalidate
            End If
            Me.segments.Clear
            Me.segments.AddRange(segments)
            If Me.connectorModified Then
                Me.Invalidate
            End If
        End Sub

        Friend Sub SetParent(ByVal parentDesigner As FreeformActivityDesigner)
            Dim parentView As WorkflowView = Me.ParentView
            If ((Not Me.parentDesigner Is Nothing) AndAlso (Not parentView Is Nothing)) Then
                parentView.InvalidateLogicalRectangle(Me.parentDesigner.Bounds)
            End If
            Me.parentDesigner = parentDesigner
            If ((Not Me.parentDesigner Is Nothing) AndAlso (Not parentView Is Nothing)) Then
                parentView.InvalidateLogicalRectangle(Me.parentDesigner.Bounds)
            End If
        End Sub

        Private Sub System.IDisposable.Dispose() Implements IDisposable.Dispose
        End Sub


        ' Properties
        Public Overridable ReadOnly Property AccessibilityObject As AccessibleObject
            Get
                If (Me.accessibilityObject Is Nothing) Then
                    Me.accessibilityObject = New ConnectorAccessibleObject(Me)
                End If
                Return Me.accessibilityObject
            End Get
        End Property

        Public ReadOnly Property Bounds As Rectangle
            Get
                Dim rectangle As Rectangle = DesignerGeometryHelper.RectangleFromLineSegments(New List([Of] Point)(Me.ConnectorSegments).ToArray)
                rectangle.Inflate(1, 1)
                Return rectangle
            End Get
        End Property

        Public ReadOnly Property ConnectorModified As Boolean
            Get
                Return Me.connectorModified
            End Get
        End Property

        Public Overridable ReadOnly Property ConnectorSegments As ReadOnlyCollection([Of] Point)
            Get
                Dim list As New List([Of] Point)
                If ((Not Me.source Is Nothing) AndAlso (Not Me.target Is Nothing)) Then
                    If ((Me.segments.Count = 0) OrElse (Not Me.segments.Item(0) Is Me.source.Location)) Then
                        list.Add(Me.source.Location)
                    End If
                    list.AddRange(Me.segments)
                    If ((Me.segments.Count = 0) OrElse (Not Me.segments.Item((Me.segments.Count - 1)) Is Me.target.Location)) Then
                        list.Add(Me.target.Location)
                    End If
                End If
                Return list.AsReadOnly
            End Get
        End Property

        Protected Friend Overridable ReadOnly Property ExcludedRoutingRectangles As ICollection([Of] Rectangle)
            Get
                Return New Rectangle(0  - 1) {}
            End Get
        End Property

        Public ReadOnly Property ParentDesigner As FreeformActivityDesigner
            Get
                Return Me.parentDesigner
            End Get
        End Property

        Protected ReadOnly Property ParentView As WorkflowView
            Get
                Return [TryCast](Me.GetService(GetType(WorkflowView)),WorkflowView)
            End Get
        End Property

        Friend ReadOnly Property RenderingOwner As FreeformActivityDesigner
            Get
                Dim associatedDesigner As ActivityDesigner
                If ((Me.source Is Nothing) OrElse (Me.target Is Nothing)) Then
                    Return Nothing
                End If
                Dim list As New List([Of] FreeformActivityDesigner)
                associatedDesigner = Me.target.AssociatedDesigner
                Do While (Not associatedDesigner Is Nothing)
                    Dim item As FreeformActivityDesigner = [TryCast](associatedDesigner,FreeformActivityDesigner)
                    If (Not item Is Nothing) Then
                        list.Add(item)
                    End If
                    associatedDesigner = associatedDesigner.ParentDesigner
                Loop
                associatedDesigner = Me.source.AssociatedDesigner
                Do While (Not associatedDesigner Is Nothing)
                    Dim designer3 As FreeformActivityDesigner = [TryCast](associatedDesigner,FreeformActivityDesigner)
                    If ((Not designer3 Is Nothing) AndAlso list.Contains(designer3)) Then
                        Exit Do
                    End If
                    associatedDesigner = associatedDesigner.ParentDesigner
                Loop
                Return [TryCast](associatedDesigner,FreeformActivityDesigner)
            End Get
        End Property

        <EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Friend ReadOnly Property Segments As List([Of] Point)
            Get
                Return Me.segments
            End Get
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Property Source As ConnectionPoint
            Get
                Return Me.source
            End Get
            Set(ByVal value As ConnectionPoint)
                If (value Is Nothing) Then
                    Throw New ArgumentNullException("value")
                End If
                If Not Me.source.Equals(value) Then
                    If (Not ConnectionManager.GetConnectorContainer(value.AssociatedDesigner) Is ConnectionManager.GetConnectorContainer(Me.target.AssociatedDesigner)) Then
                        Throw New ArgumentException(SR.GetString("Error_InvalidConnectorSource"), "value")
                    End If
                    Me.source = value
                    Me.PerformLayout
                End If
            End Set
        End Property

        <EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Friend Property SourceActivity As String
            Get
                Dim qualifiedName As String = String.Empty
                If (Not Me.source Is Nothing) Then
                    qualifiedName = Me.source.AssociatedDesigner.Activity.QualifiedName
                End If
                Return qualifiedName
            End Get
            Set(ByVal value As String)
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Content), EditorBrowsable(EditorBrowsableState.Never)> _
        Friend Property SourceConnectionEdge As DesignerEdges
            Get
                Dim none As DesignerEdges = DesignerEdges.None
                If (Not Me.source Is Nothing) Then
                    none = Me.source.ConnectionEdge
                End If
                Return none
            End Get
            Set(ByVal value As DesignerEdges)
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Content), EditorBrowsable(EditorBrowsableState.Never)> _
        Friend Property SourceConnectionIndex As Integer
            Get
                Dim connectionIndex As Integer = 0
                If (Not Me.source Is Nothing) Then
                    connectionIndex = Me.source.ConnectionIndex
                End If
                Return connectionIndex
            End Get
            Set(ByVal value As Integer)
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Property Target As ConnectionPoint
            Get
                Return Me.target
            End Get
            Set(ByVal value As ConnectionPoint)
                If (value Is Nothing) Then
                    Throw New ArgumentNullException("value")
                End If
                If Not Me.target.Equals(value) Then
                    If (Not ConnectionManager.GetConnectorContainer(value.AssociatedDesigner) Is ConnectionManager.GetConnectorContainer(Me.source.AssociatedDesigner)) Then
                        Throw New ArgumentException(SR.GetString("Error_InvalidConnectorSource"), "value")
                    End If
                    Me.target = value
                    Me.PerformLayout
                End If
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Content), EditorBrowsable(EditorBrowsableState.Never)> _
        Friend Property TargetActivity As String
            Get
                Dim qualifiedName As String = String.Empty
                If (Not Me.target Is Nothing) Then
                    qualifiedName = Me.target.AssociatedDesigner.Activity.QualifiedName
                End If
                Return qualifiedName
            End Get
            Set(ByVal value As String)
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Content), EditorBrowsable(EditorBrowsableState.Never)> _
        Friend Property TargetConnectionEdge As DesignerEdges
            Get
                Dim none As DesignerEdges = DesignerEdges.None
                If (Not Me.target Is Nothing) Then
                    none = Me.target.ConnectionEdge
                End If
                Return none
            End Get
            Set(ByVal value As DesignerEdges)
            End Set
        End Property

        <EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Friend Property TargetConnectionIndex As Integer
            Get
                Dim connectionIndex As Integer = 0
                If (Not Me.target Is Nothing) Then
                    connectionIndex = Me.target.ConnectionIndex
                End If
                Return connectionIndex
            End Get
            Set(ByVal value As Integer)
            End Set
        End Property


        ' Fields
        Private accessibilityObject As AccessibleObject
        Private connectorModified As Boolean
        Private parentDesigner As FreeformActivityDesigner
        Private segments As List([Of] Point) = New List([Of] Point)
        Private source As ConnectionPoint
        Private target As ConnectionPoint
    End Class
End Namespace

